﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using ScrumTable.Common;
using ScrumTable.DL.Data.Schema;

#endregion

namespace ScrumTable.DL.Data.Common
{
    /// <summary>
    /// Specifies the mapping of a property's get/set method.
    /// </summary>
    public class SchemaMapper
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private readonly IDictionary<string, MappingBucket> _schemaToMethodMapping;
        private readonly IDictionary<string, MappingBucket> _dataObjPropNameToMapping;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new SchemaMapper instance, no public constructor
        /// needed.
        /// </summary>
        public SchemaMapper()
        {
            _schemaToMethodMapping = new Dictionary<string, MappingBucket>();
            _dataObjPropNameToMapping = new Dictionary<string, MappingBucket>();
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new PropertyMapping instance, no public constructor
        /// needed.
        /// </summary>
        /// <param name="schema">Specifies the associated schema instance.</param>
        /// <param name="setMethod">Specifies the function pointer to the set method.</param>
        /// <param name="getMethod">Specifies the function pointer to the get method.</param>
        /// <param name="dataObjPropertyName">Specifies the data object property name. This is required because of update events from the back end system.</param>
        public void Add(SchemaBase schema, Func<SchemaBase, object> getMethod, Action<SchemaBase, object> setMethod = null, string dataObjPropertyName = null)
        {
            PreCondition.AssertNotNull(schema, "schema");
            PreCondition.AssertNotNull(getMethod, "getMethod");

            MappingBucket bucket = new MappingBucket
                                       {
                                           GetMethod = getMethod,
                                           SetMethod = setMethod,
                                           Schema = schema,
                                           DataObjectPropertyName = dataObjPropertyName
                                       };

            _schemaToMethodMapping[schema.SchemaName] = bucket;

            // default behaviour if no Data Object property name has been set: assign them to the SchemaMappedName
            if (string.IsNullOrEmpty(dataObjPropertyName))
            {
                dataObjPropertyName = schema.SchemaMappedName;
            }

            if (!string.IsNullOrEmpty(dataObjPropertyName))
            {
                _dataObjPropNameToMapping[dataObjPropertyName] = bucket;
            }
        }

        /// <summary>
        /// Returns true if the current mapper contains a mapping for the given schema field.
        /// </summary>
        /// <param name="schemaFieldName">Specifies the name of the schema field.</param>
        public bool ContainsSchema(string schemaFieldName)
        {
            return _schemaToMethodMapping.ContainsKey(schemaFieldName);
        }

        /// <summary>
        /// Gets the schema mapped set accessor method.
        /// </summary>
        /// <param name="schemaFieldName">Specifies the name of the schema field.</param>
        public Action<SchemaBase, object> GetSetMethod(string schemaFieldName)
        {
            return _schemaToMethodMapping[schemaFieldName].SetMethod;
        }

        /// <summary>
        /// Gets the schema mapped get accessor method.
        /// </summary>
        /// <param name="schemaFieldName">Specifies the name of the schema field.</param>
        public Func<SchemaBase, object> GetGetMethod(string schemaFieldName)
        {
            return _schemaToMethodMapping[schemaFieldName].GetMethod;
        }

        /// <summary>
        /// Gets the Data Object property mapped schema.
        /// </summary>
        /// <param name="dataObjPropName">Specifies the name of the Data Object property.</param>
        public SchemaBase GetSchema(string dataObjPropName)
        {
            return _dataObjPropNameToMapping[dataObjPropName].Schema;
        }

        /// <summary>
        /// Returns true if the current mapper contains a mapping for the given Data Object property.
        /// </summary>
        /// <param name="dataObjPropName">Specifies the name of the Data Object property.</param>
        public bool ContainsDataObjectProperty(string dataObjPropName)
        {
            return _dataObjPropNameToMapping.ContainsKey(dataObjPropName);
        }

        #endregion


        //--------------------------------------------------------------------
        // Nested Classes
        //--------------------------------------------------------------------

        private class MappingBucket
        {
            internal Func<SchemaBase, object> GetMethod { get; set; }
            internal Action<SchemaBase, object> SetMethod { get; set; }
            internal SchemaBase Schema { get; set; }
            internal string DataObjectPropertyName { get; set; }
        }
    }
}